﻿using Daq.Models;
using Daq.Services;
using Daq.ViewModels;
using MediaFoundation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;

namespace Daq.Devices
{

    internal class DX2204 : DaqBase
    {
        public override async Task CloseAsync(CancellationToken token)
        {
            //await webSocketClient?.ConnectAsync();

            try
            {
                // 关闭连接
                await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            client?.Dispose();
            client = new ClientWebSocket();
            client = null;
            StopPingTimer();
            isRunning = false;
        }

        public string Address { get; set; }
        public override string? Model => "DX2204";

        //private Timer _heartbeatTimer;
        //private bool _isConnected = false;
        //private DateTime _lastHeartbeatResponse = DateTime.MinValue;
        //private const int HeartbeatIntervalMs = 10000;  // 心跳发送间隔（毫秒）
        //private const int HeartbeatTimeoutMs = 30000;   // 心跳超时时间（毫秒）
        //private const int ReconnectDelayMs = 5000;      // 重连延迟（毫秒）
        //private async Task HandleConnectionFailure(string url)
        //{
        //    if (string.IsNullOrEmpty(url))
        //        return;

        //    Debug.WriteLine("尝试重新连接...");

        //    // 关闭现有连接
        //    try
        //    {
        //        client?.Dispose();
        //    }
        //    catch { }

        //    // 延迟后重连
        //    await Task.Delay(ReconnectDelayMs);
        //    await ConnectAsync(url);
        //}
        //private async void SendHeartbeat(object state)
        //{
        //    if (client == null) return;
        //    try
        //    {
        //        if (!_isConnected || client.State != WebSocketState.Open)
        //            return;

        //        // 检查上次心跳响应时间，判断是否超时
        //        if ((DateTime.UtcNow - _lastHeartbeatResponse).TotalMilliseconds > HeartbeatTimeoutMs)
        //        {
        //            Console.WriteLine("心跳超时，连接可能已断开");
        //            _heartbeatTimer?.Dispose();
        //            _isConnected = false;

        //            // 尝试重连
        //            await HandleConnectionFailure(client.Options.Uri?.ToString());
        //            return;
        //        }

        //        // 发送心跳消息
        //        var heartbeat = Encoding.UTF8.GetBytes("ping");
        //        await client.SendAsync(
        //            new ArraySegment<byte>(heartbeat),
        //            WebSocketMessageType.Text,
        //            true,
        //            _connectionCts.Token);

        //        Debug.WriteLine("已发送心跳");
        //    }
        //    catch (Exception ex)
        //    {
        //        Debug.WriteLine($"发送心跳失败: {ex.Message}");
        //        _heartbeatTimer?.Dispose();
        //        _isConnected = false;

        //        // 尝试重连
        //        await HandleConnectionFailure(client.Options.Uri?.ToString());
        //    }
        //}
        public override async Task<bool> EnsureConnection(CancellationToken token)
        {
            //webSocketClient = new WebSocketClient(
            //    $"ws://{Address}:8000/websocket",
            //    30000, // 30秒发送一次Ping
            //    5000,  // 5秒后尝试重连
            //    20,    // 最多尝试20次重连
            //    OnMessage,
            //    OnError,
            //    OnOpen,
            //    OnClose,
            //    OnReconnecting,
            //    OnReconnectSuccess,
            //    OnReconnectFailed);
            //await webSocketClient.ConnectAsync();
            //return true;

            if (client != null && client.State == WebSocketState.Open)
            {
                return true;
            }
            if(client != null && client.State == WebSocketState.Aborted)
            {
                //await client.CloseAsync(WebSocketCloseStatus.);
            }

            client = new ClientWebSocket();
            client.Options.KeepAliveInterval = TimeSpan.FromSeconds(10);
            if (string.IsNullOrWhiteSpace(Address)) return false;
            var uri = new Uri($"ws://{Address}:8000/websocket");

            var clientTask = client.ConnectAsync(uri, token);
            var timeOutTask = Task.Delay(2000, token);
            var completedTask = await Task.WhenAny(clientTask, timeOutTask);
            if (completedTask == timeOutTask)
            {
                token.ThrowIfCancellationRequested();
            }
            // 启动Ping定时器
            //StartPingTimer();
            return true;
        }

        private void OnReconnectFailed(int currentAttempt, int maxAttempts, string errorMessage)
        {
            Debug.WriteLine($"重连失败 ({currentAttempt}/{maxAttempts}): {errorMessage} (回调)");
        }

        private void OnReconnectSuccess(bool isFirstConnection)
        {
            if (isFirstConnection)
                Debug.WriteLine("首次连接成功 (回调)");
            else
                Debug.WriteLine("重连成功 (回调)");
        }

        private void OnReconnecting(int currentAttempt, int maxAttempts)
        {
            Debug.WriteLine($"正在尝试重连 ({currentAttempt}/{maxAttempts}) (回调)");
        }

        private void OnClose()
        {
            Debug.WriteLine("连接已关闭 (回调)");
        }

        private void OnOpen()
        {
            Debug.WriteLine("连接已打开 (回调)");
        }

        private void OnError(string error)
        {
            Debug.WriteLine($"错误: {error} (回调)");
        }

        private void OnMessage(string message)
        {
            Debug.WriteLine($"接收到消息: {message} (回调)");
        }

        byte[] bufferResponse = new byte[1024000];
        private bool isRunning = false;
        private DateTime daqTime;
        int count = 0;
        public override async Task<int> FetchAsync(int timeout, CancellationToken token)
        {
            await EnsureConnection(token);
            if (client == null) return 1;
            if (!isRunning)
            {
                await SendRpcRequest("start", null, 0, token);
                try
                {
                    var response = await ReceiveRpcResponse(token);
                    if (response == null)
                    {
                        return 1;
                    }
                    if (response.Result.ToString() == "0")
                    {
                        isRunning = true;
                        daqTime = DateTime.Now;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
                return 1;
            }
            else
            {
                WebSocketReceiveResult result;
                // 创建一个延迟任务，该任务将在超时时间后完成
                var delayTask = Task.Delay(timeout, token);

                CancellationTokenSource source = new();

                // 同时开始接收数据
                var receiveTask = client.ReceiveAsync(new ArraySegment<byte>(bufferResponse), source.Token);

                // 等待两个任务中的任何一个完成
                Task completedTask = await Task.WhenAny(receiveTask, delayTask);

                // 检查哪个任务完成
                if (completedTask == receiveTask)
                {
                    // 接收成功
                    result = await receiveTask;
                    var response = Encoding.UTF8.GetString(bufferResponse, 0, result.Count);
                    //Debug.WriteLine($"Received: {result.Count}");

                    int groupCount = bufferResponse[0] + (bufferResponse[1] << 8) + (bufferResponse[2] << 16) + (bufferResponse[3] << 24);
                    if(groupCount == -1)
                    {
                        //Debug.WriteLine("心跳");
                        return 1;
                    }
                    //int chCount = (result.Count - 4) / groupCount / 4;
                    //Debug.WriteLine($"groupCount: {bufferResponse[8]}");

                    int index = 4;
                    int temp = 4;
                    var value = bufferResponse[temp] + (bufferResponse[temp + 1] << 8) + (bufferResponse[temp + 2] << 16) + (bufferResponse[temp + 3] << 24);
                    //Debug.WriteLine($"cnt={result.Count},v1={value}");
                    temp = 8;
                    value = bufferResponse[temp] + (bufferResponse[temp + 1] << 8) + (bufferResponse[temp + 2] << 16) + (bufferResponse[temp + 3] << 24);
                    //Debug.WriteLine($"v2={value}");

                    if (groupCount == 0 || chCount != (result.Count - 4) / groupCount / 4)
                    {
                        Debug.WriteLine($"数据错误{count++}，group={groupCount}, chCount={chCount},resultCount={result.Count}");
                        return 1;
                    }

                    
                    //Random random = new Random();
                    for (int i = 0; i < groupCount; i++)
                    {
                        DaqMeasureData data = new DaqMeasureData();
                        daqTime = daqTime.AddMilliseconds(1);
                        data.Time = daqTime;
                        data.RawValue = new int[chCount];

                        for (int ch = 0; ch < chCount; ch++)
                        {
                            data.RawValue[ch] = bufferResponse[index] + (bufferResponse[index + 1] << 8) + (bufferResponse[index + 2] << 16) + (bufferResponse[index + 3] << 24);
                            index += 4;
                        }
                        //data.RawValue[56] = 33;
                        //if(data.RawValue[56] != 5600)
                        //Debug.WriteLine($"{chCount},{data.RawValue[56]}");
                        //Debug.WriteLine(string.Join(',', data.RawValue));
                        MeasureDataQueue.Enqueue(data);
                    }
                    return groupCount;
                }
                else if (completedTask == delayTask)
                {
                    Debug.WriteLine("接收数据超时，取消接收任务");
                    source.Cancel();
                }

                return 1;
            }
        }

        private int chCount = -1;
        public override async Task<ChannelModel[]?> GetChannelsInfoAsync(CancellationToken token)
        {
            //await GetDaqSettings(token);
            var info = await GetDaqInfo(token);
            if (info == null || info.Channels == null) return null;
            var chs = new List<ChannelModel>();
            chCount = info.Channels.Count(ch => ch.Status);
            int index = 1;
            if (info.Channels != null)
            {
                foreach (var ch in info.Channels)
                {
                    if (!ch.Status) continue;
                    chs.Add(new ChannelModel
                    {
                        Type = DaqDevice.GetChannelType(ch.Unit),
                        Unit = ch.Unit,
                        RangeMax = 100,
                        RangeMin = 0,
                        Index = index++,
                        IsEnabled = ch.Status,
                        Color = ch.Color,
                        Name = ch.Alias??"",
                        Digits = ch.Digits
                    });
                }
            }
            MeasureData.Channels = [.. chs];
            return [.. chs];
        }

        public override Task<double> GetSampleRateAsync(CancellationToken token)
        {
            return Task.FromResult(0.001);
        }


        private async Task SendHeartbeat(CancellationToken token)
        {
            try
            {
                await SendRpcRequest("ping", null, 0, token);
                await ReceiveRpcResponse(token);
            }
            catch { }
        }
        private async Task SendRpcRequest(string methodName, object parameters, int id, CancellationToken token)
        {
            await EnsureConnection(token);
            if (client == null) return;
            // 发送JSON-RPC请求
            var request = new JsonRpcRequest
            {
                Method = methodName,
                Params = parameters,
                Id = id
            };
            var json = JsonSerializer.Serialize(request);
            var buffer = Encoding.UTF8.GetBytes(json);
            var segment = new ArraySegment<byte>(buffer);
            try
            {
                await client.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            catch(Exception ex)
            {
                client = null;
                Debug.WriteLine(ex.Message);
            }
        }

        private async Task<JsonRpcResponse?> ReceiveRpcResponse(CancellationToken token)
        {
            await EnsureConnection(token);
            if (client == null) return null;
            DateTime startTime = DateTime.Now;
            while(!token.IsCancellationRequested)
            {
                var result = await client.ReceiveAsync(new ArraySegment<byte>(bufferResponse), CancellationToken.None);
                if (result.MessageType != WebSocketMessageType.Text)
                {
                    await Task.Delay(10, token);
                    continue;
                }
                var response = Encoding.UTF8.GetString(bufferResponse, 0, result.Count);
                try
                {
                    var jsonResponse = JsonSerializer.Deserialize<JsonRpcResponse>(response);
                    return jsonResponse;
                }
                catch
                {
                    return null;
                }
                if((DateTime.Now - startTime).TotalSeconds >= 2)
                {
                    return null;
                }
            }
            return null;
        }

        private ClientWebSocket? client;

        private async Task<byte[]?> ReceiveAsync(TimeSpan timeout, CancellationToken cancellationToken)
        {
            if (client == null) return null;
            WebSocketReceiveResult result;
            // 创建一个延迟任务，该任务将在超时时间后完成
            var delayTask = Task.Delay(timeout, cancellationToken);

            // 同时开始接收数据
            var receiveTask = client.ReceiveAsync(new ArraySegment<byte>(bufferResponse), CancellationToken.None);

            // 等待两个任务中的任何一个完成
            Task completedTask = await Task.WhenAny(receiveTask, delayTask);

            // 检查哪个任务完成
            if (completedTask == receiveTask)
            {
                // 接收成功
                result = await receiveTask;
                byte[] array = new byte[result.Count];
                //Debug.WriteLine(result.Count);
                Array.Copy(bufferResponse.ToArray(), array, result.Count);
                return array;
            }
            else if (completedTask == delayTask)
            {
                cancellationToken.ThrowIfCancellationRequested();
            }
            return null;
        }

        public static string TruncateUtf8String(string input, int maxLength)
        {
            byte[] encodedBytes = Encoding.UTF8.GetBytes(input);

            // 如果原始字符串转换后的长度超过最大长度，则进行截断
            if (encodedBytes.Length > maxLength)
            {
                // 使用 StringBuilder 来构建截断后的字符串
                var sb = new System.Text.StringBuilder();
                int bytesWritten = 0;

                for (int i = 0; i < input.Length; i++)
                {
                    char c = input[i];
                    byte[] currentCharBytes = Encoding.UTF8.GetBytes(c.ToString());

                    // 检查添加当前字符后是否超过了最大长度
                    if (bytesWritten + currentCharBytes.Length <= maxLength)
                    {
                        sb.Append(c);
                        bytesWritten += currentCharBytes.Length;
                    }
                    else
                    {
                        // 如果添加当前字符会导致长度超过最大长度，且当前字符是多字节字符，则跳过该字符
                        if (currentCharBytes.Length > 1)
                        {
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                // 返回截断后的字符串
                return sb.ToString();
            }

            // 如果不需要截断，则直接返回原始字符串
            return input;
        }

        private string tempSettingFilePath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "";
        public override async Task SendDaqSettings(CancellationToken token)
        {
            if (DaqSettings == null)
            {
                return;
            }

            if (Settings == null)
            {
                Settings = new();
            }

            //Settings.DaqsSettings.Instance.Daqs ??= [];

            //if (Settings.DaqsSettings.Instance.Daqs.FirstOrDefault(daq => daq.SN == DaqSettings.SN) == null)
            //{
            //    Settings.DaqsSettings.Instance.Daqs.Add(DaqSettings);
            //}
            //else
            //{
            //    for(int i = 0; i < Settings.DaqsSettings.Instance.Daqs.Count; i++)
            //    {
            //        if (Settings.DaqsSettings.Instance.Daqs[i].SN == SN)
            //        {
            //            Settings.DaqsSettings.Instance.Daqs[i] = DaqSettings;
            //            break;
            //        }
            //    }
            //}

            await SendDaqSettings(DaqSettings, token);
            //await Task.WhenAll([Settings.DaqsSettings.Save(), SendDaqSettings(DaqSettings, token)]);
        }

        private async Task SendDaqSettings(DaqSettings? settings, CancellationToken token)
        {
            if (settings == null) return;
            string str = JsonSerializer.Serialize(settings);
            await SendRpcRequest("set_daq_info", new string[] { str }, 0, token);
            Debug.WriteLine("设置DAQ参数：" + str);
            var response = await ReceiveRpcResponse(token);
        }

        private struct DaqChannelInfoJson
        {
            [JsonPropertyName("status")]
            public bool Status { get; set; }
            [JsonPropertyName("digits")]
            public int Digits { get; set; }
        }
        private struct DaqInfoJson
        {
            [JsonPropertyName("channels")]
            public List<DaqChannelInfoJson> Channels { get; set; }
        }
        public override async Task SendDaqSettings(DaqInfo daqInfo, CancellationToken token)
        {
            DaqInfoJson daqInfoJson = new();
            daqInfoJson.Channels = [];
            if(daqInfo.Channels != null)
            {
                foreach (var ch in daqInfo.Channels)
                {
                    daqInfoJson.Channels.Add(new DaqChannelInfoJson { Status = ch.Status, Digits = ch.Digits });
                }
            }
            string str = JsonSerializer.Serialize(daqInfoJson);
            await SendRpcRequest("set_daq_info", new string[] { str }, 0, token);
            Debug.WriteLine("设置DAQ参数：" + str);
            var response = await ReceiveRpcResponse(token);
        }

        public override async Task<bool> GetSetDaqSettingsStatus(CancellationToken token)
        {
            await SendRpcRequest("get_daq_info_set_status", null, 0, token);
            var response = await ReceiveRpcResponse(token);
            var result = response.Result.ToString();
            //if ()
            //{
            //    return false;
            //}
            Debug.WriteLine("result=" + result);
            return result == "0";
        }

        public override async Task<DaqInfo?> GetDaqInfo(CancellationToken token = default)
        {
            await SendRpcRequest("get_daq_info", null, 0, token);
            string? responseText;
            //DaqSettings? settings = null;
            DaqInfo? info = null;
            chCount = -1;
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    var result = await ReceiveAsync(TimeSpan.FromMilliseconds(1000), new CancellationToken());
                    if (result == null || result.Length == 0) continue;
                    var response = Encoding.UTF8.GetString(bufferResponse, 0, result.Length);
                    Debug.WriteLine($"Received {response}");
                    JsonRpcResponse? r = JsonSerializer.Deserialize<JsonRpcResponse>(response);
                    if (r == null || r.Result == null) continue;
                    responseText = r.Result.ToString();
                    if (responseText == null) continue;
                    Debug.WriteLine(responseText);
                    info = JsonSerializer.Deserialize<DaqInfo>(responseText);
                    if(info != null)
                    {
                        info.Instance = this;
                        chCount = info.Channels.Where(ch => ch.Status).Count();
                        Debug.WriteLine($"ChCount={chCount}");
                    }
                    break;
                }
                catch (Exception ex)
                {
                    //await File.AppendAllTextAsync("./response.txt", $"{DateTime.Now.ToString()}\n{responseText}\n\n");
                    Debug.WriteLine($"Error: {ex.Message}");
                }
            }
            
            return info;
        }

        private async Task<DaqSettings?> GetDaqSettings(CancellationToken token)
        {
            await SendRpcRequest("get_daq_info", null, 0, token);
            string responseText = "";
            // 接收服务器的响应
            //var result = await client.ReceiveAsync(new ArraySegment<byte>(bufferResponse), CancellationToken.None);
            //DaqSettings = new();
            DaqSettings? settings = null;
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    var result = await ReceiveAsync(TimeSpan.FromMilliseconds(1000), new CancellationToken());
                    if (result == null || result.Length == 0) continue;
                    var response = Encoding.UTF8.GetString(bufferResponse, 0, result.Length);
                    Debug.WriteLine($"Received {response}");
                    JsonRpcResponse r = JsonSerializer.Deserialize<JsonRpcResponse>(response);
                    responseText = r.Result.ToString();
                    settings = JsonSerializer.Deserialize<DaqSettings>(responseText);
                    break;
                }
                catch (Exception ex)
                {
                    //await File.AppendAllTextAsync("./response.txt", $"{DateTime.Now.ToString()}\n{responseText}\n\n");
                    Debug.WriteLine($"Error: {ex.Message}");
                }
            }

            if (settings != null && settings.Channels != null)
            {
                int index = 1;
                foreach (var ch in settings.Channels)
                {
                    ch.Index = index;
                    ch.GroupIndex = (index - 1) / 8 + 1;
                    ch.Alias = $"CH{index}";
                    index++;
                }
            }

            //从配置文件中获取通道配置
            if (Settings == null || Settings.DaqsSettings.Instance.Daqs == null)
            {
                DaqSettings = settings;
                return DaqSettings;
            }
            var localSettings = Settings.DaqsSettings.Instance.Daqs.FirstOrDefault(daq => daq.SN == SN);
            if (localSettings == null)
            {
                DaqSettings = settings;
                return DaqSettings;
            }

                //对比本地和设备的配置差异
            if (settings != null && settings.SN == localSettings.SN && settings.Channels != null)
            {
                for (int i = 0; i < settings.Channels.Count; i++)
                {
                    settings.Channels[i].Alias = localSettings.Channels[i].Alias;
                    settings.Channels[i].Unit = localSettings.Channels[i].Unit;
                    settings.Channels[i].Digits = localSettings.Channels[i].Digits;
                    settings.Channels[i].Color = localSettings.Channels[i].Color;
                    if (settings.Channels[i].IsEnabled)
                    {
                        settings.Channels[i].Status = localSettings.Channels[i].Status;
                    }
                    else
                    {
                        settings.Channels[i].Status = false;
                    }
                }
            }
            
            DaqSettings = settings;
            return DaqSettings;
        }

        public override async Task OpenAsync(string address, CancellationToken token)
        {
            this.Address = address;
            await EnsureConnection(token);
        }
        private Timer _pingTimer;
        public DX2204(string sn = "") : base(sn)
        {
        }

        public static async Task<List<DeviceInfo>?> SearchAsync(CancellationToken token)
        {
            return await DxDaq.SearchDevices();
        }

        public override async Task<bool> ModifyAddress(object address, CancellationToken token)
        {
            if (address is string[] array && array.Length == 2)
            {
                await SendRpcRequest("set_ip_address", array, 0, token);
                var result = await ReceiveRpcResponse(token);
                return true;
            }
            return false;
        }

        public override async Task StopAsync(CancellationToken token)
        {
            try
            {
                await SendRpcRequest("stop", null, 0, token);
                await ReceiveRpcResponse(token);
            }
            catch { }
        }

        // 启动定时Ping
        private void StartPingTimer()
        {
            StopPingTimer();

            _pingTimer = new System.Threading.Timer(
                async _ => await SendPingAsync(),
                null,
                1000,
                1000);

            Debug.WriteLine($"Ping定时器已启动");
        }

        // 发送Ping帧
        private async Task SendPingAsync()
        {
            if (client == null || client.State != WebSocketState.Open)
            {
                Debug.WriteLine("无法发送Ping，连接未建立或已关闭");
                return;
            }

            try
            {
                //var pingData = Encoding.UTF8.GetBytes("Ping");
                //await client.SendAsync(
                //    new ArraySegment<byte>(pingData),
                //    WebSocketMessageType.Binary,
                //    true,
                //    CancellationToken.None);
                await SendRpcRequest("ping", null, 0, CancellationToken.None);

                Debug.WriteLine($"发送Ping: {DateTime.Now}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"发送Ping失败: {ex.Message}");
                //await CloseConnectionAsync();
            }
        }

        // 停止定时Ping
        private void StopPingTimer()
        {
            _pingTimer?.Dispose();
            _pingTimer = null;
        }
    }
}
